layui.define(["jmTpl"], function (exports) {
    "use strict";
    // jQuery
    let $ = layui.$
    // 模板引擎
    let jmTpl = layui.jmTpl
    // mainView对象
    let mainViewElement
    // 当前模板
    let template = ""
    // 监听数据
    let proxyObj = {}
    // 初始化配置
    let config = {
        main: "home",
        view: "main-view",
        mode: "hash"
    }
    // 当前页面
    let thisUrl = "";
    // 缓存数据
    let CacheData = {}
    // 路由
    let routes = {}

    // 事件
    const linkList = () => {
        onDestroy(app.onDestroy)
        mainViewElement.removes();
        jump();
    }

    //监听 哈希 事件
    window.addEventListener('hashchange', linkList);

    // 监听 popstate 事件
    window.addEventListener('popstate', linkList);

    /**
     * 设置缓存
     * @param {string} page 
     * @param {object} obj 
     */
    let setCache = (page, obj = {}) => {
        if (typeof CacheData[page] == "undefined") {
            CacheData[page] = obj
        }
        else if (Object.keys(obj).length) {
            CacheData[page] = obj
        }
    }

    /**
     * 获取缓存
     * @param {string} page 
     * @returns 
     */
    let getCache = (page) => {
        return CacheData[page]
    }

    /**
     * 清除缓存
     * @param {string} page 
     */
    let delCache = (page) => {
        delete CacheData[page]
    }

    /**
     * 挂载
     * @param {callback} callback 
     */
    let onMount = (callback) => {
        callback()
    }

    /**
     * 渲染前
     * @param {callback} callback 
     */
    let beforeUpdate = (callback) => {
        callback()
    }

    /**
     * 渲染后
     * @param {callback} callback 
     */
    let afterUpdate = (callback) => {
        let doc = $(document.querySelector(config.view).shadowRoot)
        callback(doc)
        layui.form.render($(doc).find(".layui-form"));
    }

    /**
     * 卸载
     * @param {callback} callback 
     */
    let onDestroy = (callback) => {
        callback()
        app.onMount = () => { }
        app.beforeUpdate = () => { }
        app.afterUpdate = () => { }
        app.onDestroy = () => { }
        proxyObj = {}
    }

    // 模板渲染
    const templateUpload = async (str = template) => {
        let div = mainViewElement.shadowRoot.querySelector("div[id=template]")
        if (Object.keys(proxyObj).length > 0) {
            beforeUpdate(app.beforeUpdate)
            div.innerHTML = jmTpl(str, proxyObj)
            afterUpdate(app.afterUpdate)
        } else {
            div.innerHTML = str
        }
    }

    /**
     * 跳转
     */
    const jump = async () => {
        const arr = layui.url()
        let htmlView;
        if (arr.pathname[0] === "" && typeof arr.hash.href === "undefined") {
            htmlView = config.main;
        } else {
            const checkedPaths = {};
            const mode = config.mode;
            const joinPathFunc = mode === "history" ? (arr) => `/${arr.pathname.join("/")}` : (arr) => `/${arr.hash.path.join("/")}`;

            for (const [key, value] of Object.entries(routes)) {
                const joinedPathname = joinPathFunc(arr);
                if (!checkedPaths[joinedPathname] && value.route.includes(joinedPathname)) {
                    htmlView = key;
                    checkedPaths[joinedPathname] = true;
                }
            }
        }
        
        if (typeof htmlView === "undefined") {
            if (typeof routes.fallback !== "undefined") {
                htmlView = "fallback"
            } else {
                console.error("没有配置相关路由", arr)
                return
            }
        }

        let url = `${routes[htmlView].page}/${routes[htmlView].page.split("/").at(-1)}`
        thisUrl = url
        setCache(thisUrl)
        let res = await jqGet(url + ".html")
        template = res
        mainViewElement.render(url)
        // await templateUpload(template)
    }

    /**
     * jqGet
     * @param {string} url 
     * @returns 
     */
    const jqGet = async function (url) {
        return await $.get(url).then(res => {
            return res
        })
    }

    /**
     * 预加载链接
     * @param {string} url 链接
     */
    const preloadLink = function (url) {
        try {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.send();
        } catch (error) {
            console.error(`预加载链接时出错: ${error}`);
        }
    }

    /**
     * 加载 路由
     * @param {object} data 对象
     */
    const LoadRoute = async function (data) {
        for (const [key, value] of Object.entries(data)) {
            const page = value.page.split("/")
            preloadLink(`${value.page}/${page.at(-1)}.js`)
            preloadLink(`${value.page}/${page.at(-1)}.css`)
            preloadLink(`${value.page}/${page.at(-1)}.html`)
        }
    }

    /**
     * 自定义元素
     */
    class WebComponents extends HTMLElement {
        constructor() {
            super();
            // 创建 Shadow DOM
            const shadowRoot = this.attachShadow({ mode: 'open' });
        }

        // 公共样式
        common() {
            let common = document.createElement("div")
            common.id = "common"
            let css = "";
            $("link[common]").each(function (k, v) {
                css += `<link rel="stylesheet" href="${$(v).attr("href")}">`
            })
            common.innerHTML = css;
            this.shadowRoot.appendChild(common)
        }

        // 渲染
        render(url) {
            let view = document.createElement("div")
            view.id = "view"
            this.shadowRoot.appendChild(view)
            let script = document.createElement("script")
            script.src = url + ".js"
            let css = document.createElement("link")
            css.rel = "stylesheet"
            css.href = url + ".css"
            let template = document.createElement("div")
            template.id = "template"
            view.appendChild(css)
            view.appendChild(script)
            view.appendChild(template)
            // 判断是否加载完成
            script.onload = () => {
                onMount(app.onMount)
                templateUpload()
            }

        }

        // 清空
        removes() {
            // 移除div的id为view的内容
            const view = this.shadowRoot.getElementById("view");
            if (view) {
                this.shadowRoot.removeChild(view);
            }
        }
    }

    let app = {
        // 渲染
        render: async (options) => {
            config.main = options.main || config.main
            config.view = options.view || config.view
            config.mode = options.mode || config.mode

            routes = await jqGet(options.route)
            await LoadRoute(routes)

            // 注册自定义元素
            customElements.define(config.view, WebComponents);
            mainViewElement = document.querySelector(config.view);
            mainViewElement.common()
            jump();
        },
        /**
         * 数据监听
         * @param {object} object 
         * @returns 
         */
        proxy: (object) => {
            if (!Object.keys(object).length) {
                return proxyObj
            }
            if (Object.keys(getCache(thisUrl)).length) {
                object = getCache(thisUrl)
            }
            proxyObj = new Proxy(object, {
                get(target, property, receiver) {
                    try {
                        return new Proxy(target[property], {
                            set(childTarget, childProperty, value) {
                                const result = Reflect.set(childTarget, childProperty, value);
                                setCache(thisUrl, target)
                                proxyObj = target
                                templateUpload()
                                return result;
                            },
                        });
                    } catch (e) {
                        return Reflect.get(target, property, receiver);
                    }
                },
                set(target, property, value) {
                    const result = Reflect.set(target, property, value);
                    setCache(thisUrl, target)
                    proxyObj = target
                    templateUpload()
                    return result;
                },
            })
            return proxyObj;
        },
        // 挂载
        onMount: () => { },
        // 渲染前
        beforeUpdate: () => { },
        // 渲染后
        afterUpdate: () => { },
        // 卸载
        onDestroy: () => { },
        // 清理数据
        clearCache: () => {
            delCache(thisUrl)
        },
        /**
         * 跳转函数
         * @param {string} navigate 页面
         * @param {string} param 参数
         */
        navigateTo: function (navigate, param = "") {
            if (typeof routes[navigate] !== "undefined") {
                navigate = routes[navigate].route[0]
            }
            if (config.mode == "history") {
                if (param.trim() !== "") {
                    param = `?${param.replace(",", "&")}`
                }
                history.pushState({}, navigate, navigate + param);
            } else {
                if (param.trim() !== "") {
                    param = `/${param.replace(",", "/")}`
                }
                window.location.href = `/#${navigate}${param}`
            }
            linkList()
        }
    }

    exports('app', app); // 输出模块
});  